home *** CD-ROM | disk | FTP | other *** search
- *****************************************************************************
- * Program: newser.asm - Copyright © 1990, 1991 by Dan Babcock
- *
- * Permission is given for PERSONAL use of this code. Commercial
- * use is of course forbidden. (Without prior permission etc.)
- *
- * Function: A "serial.device" compatible driver for the Rockwell 65C52
- *
- * Author: Dan Babcock
- * History: 08/12/90 V0.50 Created
- * 09/06/90 V0.51 Cleaned up "eofdump" code.
- * 11/04/90 V0.52 Misc. minor changes
- * [release 1]
- * 03/03/91 V1.10 Fixed some bugs, speeded up, & added prefs hook
- * 03/08/91 V1.11 Bug fixes
- * [release 2]
- * 04/18/91 V1.12 Small changes (very small)
- * 06/20/91 V2.00 Bug fixes, code clean-up, faster
- * [release 3]
- * 06/27/91 V2.10 Added ASDG-style DTR/RTS control extension
- * (See "SetControlLines" for documentaion)
- * Added special time-out to write routine to
- * avoid theoretical (and possibly real) problem
- * Fixed bug in Break routine
- * [release 4]
- *
- * Feel free to contact me:
- *
- * [School address] [Permanent address] People/Link:
- * Subject to Dan Babcock DANBABCOCK
- * change so not P.O. Box 1532 Bix:
- * given here Southgate, MI 48195 danbabcock
- * U.S.A.
- *
- * I am also reachable via internet. I read comp.sys.amiga.programming.
- *
- * General notes
- * =============
- * The macro "PUTDEBUG" is used to output debugging information via the
- * internal serial port at a low level. It may be used anywhere, including
- * critical sections, supervisor mode, and interrupt code. If debugging is
- * not desired, set the INFO_LEVEL equate to zero. Conversely, if debugging
- * is desired, set it to a high value (e.g. 100000)
- *
- * A consistent (for the most part) usage of registers was employed:
- * A1 - pointer to an IORequest structure
- * A3 - pointer to a unit structure (defined below)
- * A4 - pointer to a serprefs structure (defined below)
- * A5 - pointer to the hardware (one channel, that is)
- * A6 - pointer to the device structure (defined below)
- *
- * Known differences between this and serial.device are:
- * 1. Start/Stop do not send XON/XOFF characters to the outside world
- * as implied in the autodoc. (I doubt anyone uses Start and Stop...)
- * 2. Newser does not currently send an XOFF or otherwise tell the outside
- * world to "shut up" when the driver's input buffer fills.
- * Since the buffer is 64K, it is very unlikely to ever fill.
- * Both of those capabilities can be added external to the driver if you
- * have a custom application that requires them.
- *****************************************************************************
-
- MC68010
- super ;suppress warnings about supervisor mode
- exeobj
- objfile 'devs:newser.device'
- macfile 'newser.i'
-
- ;Set INFO_LEVEL to a high number (e.g. 100000) for full debugging output
- ;over the internal serial port.
- INFO_LEVEL equ 000000
-
- EXEC macro
- move.l a1,-(sp)
- move.l a6,-(sp)
- movea.l (4).w,a6
- jsr (_LVO\1,a6)
- movea.l (sp)+,a6
- movea.l (sp)+,a1
- endm
-
- ;*************************** Structures *************************
-
- serprefs clrso
- prefs_CTLCHAR so.l 1 ;Control char's (order = xON,xOFF,rsvd,rsvd)
- prefs_RBUFLEN so.l 1 ;Length in bytes of serial port's read buffer
- prefs_EXTFLAGS so.l 1 ;Additional serial flags
- prefs_BAUD so.l 1 ;Baud rate requested (true baud)
- prefs_BRKTIME so.l 1 ;Duration of break signal in MICROseconds
- prefs_TERMARRAY so.b TERMARRAY_SIZE ;Termination character array
- prefs_READLEN so.b 1 ;Bits per read char (bit count)
- prefs_WRITELEN so.b 1 ;Bits per write char (bit count)
- prefs_STOPBITS so.b 1 ;Stopbits for read (count)
- prefs_SERFLAGS so.b 1 ;See SERFLAGS bit definitions
- serprefs_sizeof soval
-
- MyDev setso LIB_SIZE
- md_Flags so.b 1
- md_Pad1 so.b 1
- md_SysLib so.l 1
- md_SegList so.l 1
- md_Units so.b MD_NUMUNITS*4
- VectorBase so.l 1
- MyPreviousAutoVec: so.l 1
- ScoreBoard so.w 1
- Chip1present so.w 1
- Chip2present so.w 1
- prefs_unit0 so.b serprefs_sizeof ;The reason why prefs are in this
- prefs_unit1 so.b serprefs_sizeof ;structure instead of the unit structure
- prefs_unit2 so.b serprefs_sizeof ;is that the pref settings should be saved
- prefs_unit3 so.b serprefs_sizeof ;across CloseDevice calls (which usually
- MyDev_Sizeof soval ;causes the unit to be dumped).
-
- MyDevUnit setso UNIT_SIZE ;Odd # longwords
- mdu_wport so.b MP_SIZE ;MsgPort for write task
- MDU_FLAGS so.b 1
- IERstate so.b 1 ;Current state of IER used as a mask
- mdu_UnitNum so.b 1
- frstate so.b 1 ;This var mirrors a write-only register
- mdu_SysLib so.l 1 ;Copy of location 4
- mdu_Device so.l 1 ;Ptr to main device struct
- mdu_rstack so.b MYPROCSTACKSIZE ;For read task
- mdu_wstack so.b MYPROCSTACKSIZE ;For write task
- mdu_rtcb so.b TC_SIZE ;Task Control Block (TCB) for read task
- mdu_wtcb so.b TC_SIZE ;Task Control Block (TCB) for write task
- timerport so.b MP_SIZE
- timeriorequest so.b IOTV_SIZE
-
- ;The -sig longwords must be contiguous!!!
- readsig so.l 1 ;Read task signals
- readabortsig so.l 1
-
- tdresig so.l 1 ;Write block finished
- writeabortsig so.l 1
- xonsig so.l 1 ;Comes from read task, and indicates xon received
-
- HeadLong so.w 1 ;Ptr to start of circular buffer (logical)
- Head so.w 1
- TailLong so.w 1 ;Ptr to end of circular buffer (logical)
- Tail so.w 1
- StartBuf so.l 1 ;Ptr to physical start of input buffer
- ReadRequestPtr so.l 1
- WriteRequestPtr so.l 1
- xstate so.b 1 ;Zero if 'x-off' received, else $FF
- ISRcopy so.b 1 ;Used for read error diagnosis
- CSRcopy so.b 1 ;Used for read error diagnosis
- Exclusive so.b 1 ;True if someone has exclusive access to this unit
- daciabase so.l 1
- mdu_prefs so.l 1 ;Ptr to prefs for this unit (in MyDev)
- WriteCount so.l 1
- WriteBufferPtr so.l 1
- MyDevUnit_Sizeof soval
-
- ;Note that we have a single unit structure used by both the read and write
- ;tasks (and the interrupt routine).
-
- * UNIT_FLAG definitions:
-
- BITDEF UNIT,BREAKSENT,2 ;break sent flag for Query
- BITDEF UNIT,READIMMEDIATE,3
- BITDEF UNIT,NEEDCHAR,4
-
- * Bit definitions for MDU_FLAGS
-
- BITDEF MDU,STOPPED,2 ;State bit for unit stopped
- BITDEF MDU,V,3 ;Buffer overflow flag - set in int routine if an overflow occurs
- BITDEF MDU,WaitingForChar,4
- BITDEF MDU,CharAvailable,5
-
- * Bit definitions for ioflags
-
- BITDEF ioflags,Ignore,4 ;Ignore this IO request
-
- * Equates & bit defs for IERstate
-
- READINT equ $87
- READINTMASK equ $7
-
- WRITEINT equ $C0
- WRITEINTMASK equ $40
-
- MYIDENT macro
- cstr 'newser.device V2.10 (June 27, 1991)',13,10
- even
- endm
-
- ;The first executable location. This should return an error in case someone
- ;tried to run us as a program (instead of loading us as a device).
-
- FirstAddress:
- moveq #-1,d0
- rts
-
- ;A romtag structure. After your driver is brought in from disk, the
- ;disk image will be scanned for this structure to discover magic constants
- ;about you (such as where to start running you from...).
-
- initDDescrip:
- dw RTC_MATCHWORD ;UWORD RT_MATCHWORD (Magic cookie)
- dl initDDescrip ;APTR RT_MATCHTAG (Back pointer)
- dl EndCode ;APTR RT_ENDSKIP (To end of this hunk)
- db RTF_AUTOINIT ;UBYTE RT_FLAGS (magic-see "Init")
- db VERSION ;UBYTE RT_VERSION
- db NT_DEVICE ;UBYTE RT_TYPE (must be correct)
- db MYPRI ;BYTE RT_PRI
- dl myName ;APTR RT_NAME (exec name)
- dl idString ;APTR RT_IDSTRING (text string)
- dl Init ;APTR RT_INIT
-
- db 'newser.device - Copyright (c) 1990, 1991 by Dan Babcock. '
- db 'Contact me on People/Link, Bix, or Usenet!'
- even
-
- ;nasty data area (makes this version non-ROMable)
-
- OldVec: dc.l 0
- Unit0: dc.l 0
- Unit1: dc.l 0
- _Unit2: dc.l 0 ;_ used because of conflict with chip reg addr sym
- Unit3: dc.l 0
-
-
- ;*********************** Tables (constant) **********************
-
- ;Note!! Some of these values are depended on in the InitRoutine prefs
- ;code...i.e. they may not be changed arbitrarily!
-
- defaultprefs:
- dl SER_DEFAULT_CTLCHAR ;prefs_CTLCHAR
- dl 64*1024 ;prefs_RBUFLEN
- dl 0 ;prefs_EXTFLAGS
- dl 9600 ;prefs_BAUD
- dl 250000 ;prefs_BRKTIME
- dl 0 ;prefs_TERMARRAY
- dl 0 ;prefs_TERMARRAY
- db 8 ;prefs_READLEN
- db 8 ;prefs_WRITELEN
- db 1 ;prefs_STOPBITS
- ;Note: RAD_BOOGIE must NOT be set here
- db $88 ;prefs_SERFLAGS
-
- ;Table of DACIA base addresses for the 4 units
-
- basetable:
- dl ACIA_Base
- dl ACIA_Base+UNIT2
- dl ACIA_Base+ACIA1
- dl ACIA_Base+ACIA1+UNIT2
-
- ;List of supported baud rates
-
- baudtable:
- dw 50
- dw 110
- dw 135
- dw 150
- dw 300
- dw 600
- dw 1200
- dw 1800
- dw 2400
- dw 3600
- dw 4800
- dw 7200
- dw 9600
- dw 19200
- dw 38400
- dw 31250 ;MIDI (external clock)
-
- timername:
- cstr 'timer.device'
-
- ifne INFO_LEVEL ;If any debugging enabled at all
- subSysName:
- cstr 'newser' ;This name for debugging use
- endc
-
- myName: MYDEVNAME ;This is the name that the device will have
-
- ;This is an identifier tag to help in supporting the device
- ;format is 'name version.revision (dd MON yyyy)',<cr>,<lf>,<null>
-
- idString: MYIDENT
-
- ;The romtag specified that we were "RTF_AUTOINIT". This means that the
- ;RT_INIT structure member points to one of these tables below. If the
- ;AUTOINIT bit was not set then RT_INIT would point to a routine to run.
-
- Init: dl MyDev_Sizeof ;data space size
- dl FuncTable ;pointer to function initializers
- dl DataTable ;pointer to data initializers
- dl InitRoutine ;routine to run
-
- FuncTable:
- dw -1 ;this indicates that the following are offsets,
- ;rather than absolute addresses
- dw Open-FuncTable ;standard system routines
- dw _Close-FuncTable
- dw Expunge-FuncTable
- dw Null-FuncTable ;Reserved for future use!
- dw BeginIO-FuncTable ;my device definitions
- dw AbortIO-FuncTable
- dw -1 ;function table end marker
-
- ;The data table initializes static data structures. The format is
- ;specified in exec/InitStruct routine's manual pages. The
- ;INITBYTE/INITWORD/INITLONG macros are in the file "exec/initializers.i".
- ;The first argument is the offset from the device base for this
- ;byte/word/long. The second argument is the value to put in that cell.
- ;The table is null terminated
-
- DataTable:
- INITBYTE LN_TYPE,NT_DEVICE ;Must be LN_TYPE!
- INITLONG LN_NAME,myName
- INITBYTE LIB_FLAGS,LIBF_SUMUSED+LIBF_CHANGED
- INITWORD LIB_VERSION,VERSION
- INITWORD LIB_REVISION,REVISION
- INITLONG LIB_IDSTRING,idString
- dw 0 ;terminate list
-
- ;This routine gets called after the device has been allocated. The device
- ;pointer is in D0. The AmigaDOS segment list is in a0. If it returns the
- ;device pointer, then the device will be linked into the device list. If it
- ;returns NULL, then the device will be unloaded.
- ;
- ;This call is single-threaded by exec; please read the description for
- ;"Open" below.
- ;
- ; Register Usage
- ; ==============
- ; a3 -- Points to temporary RAM
- ; a4 -- Expansion library base
- ; a5 -- device pointer
- ; a6 -- Exec base
-
- InitRoutine:
- PUTDEBUG 5,<'%s/Init: called'>
- movem.l d1-d7/a0-a6,-(sp) ;Preserve ALL modified registers
-
- movea.l d0,a5
- move.l a6,(md_SysLib,a5) ;Save a pointer to exec
- move.l a0,(md_SegList,a5) ;Save pointer to our loaded code
-
- ;Check for presence/absence of the 2 serial chips
- moveq #0,d0
- moveq #0,d1
- move.l #ACIA_Base,a4
- move.b #$83,(FMR,a4)
- move.b (CSR,a4),d2
- and.b #3,d2
- cmp.b #3,d2
- bne.b .Chip2
- move.b #$80,(FMR,a4)
- move.b (CSR,a4),d2
- and.b #3,d2
- bne.b .Chip2
- moveq #-1,d0
- .Chip2:
- move.l #ACIA_Base+ACIA1,a4
- move.b #$83,(FMR,a4)
- move.b (CSR,a4),d2
- and.b #3,d2
- cmp.b #3,d2
- bne.b .Done
- move.b #$80,(FMR,a4)
- move.b (CSR,a4),d2
- and.b #3,d2
- bne.b .Done
- moveq #-1,d1
-
- .Done:
- move.w d0,(Chip1present,a5)
- move.w d1,(Chip2present,a5)
-
- ;Take over level 6 autovector (nasty, but justified)
- clr.l (VectorBase,a5)
- tst.w (AttnFlags,a6)
- beq.b .skipvbr
-
- SYS SuperState
- movec vbr,a2
- bsr MyUserState
-
- move.l a2,(VectorBase,a5)
- .skipvbr:
- move.l (VectorBase,a5),a0
- move.l ($78,a0),(OldVec)
- move.l #Int0000,($78,a0)
- move.l #Int0000,(MyPreviousAutoVec,a5)
- move.l a5,a6
- bsr SetDefaultPrefs
- move.l (4).w,a6
-
- ;Try to find the prefs in memory
- lea (MagicPortName,pc),a1
- SYS FindPort
- tst.l d0
- beq .EndInit ;use hard-coded defaults
- move.l d0,a0
- lea (MP_SIZE,a0),a3
- move.l a5,a6
- lea (prefs_unit0,a6),a2
-
- moveq #3,d7 ;4 units
- moveq #0,d5
-
- .OuterLoop:
- move.l d5,d6
- lsl.w #3,d6 ;Convert unit # to index
- move.l a3,a1
- lea (a1,d6.w),a1 ;UnitPrefs for this unit
- .PrefsLoop:
- moveq #0,d0
- move.w #512,d0
- moveq #0,d1
- move.w (up_BufSize,a1),d1 ;0-7
- lsl.l d1,d0
- move.l d0,(prefs_RBUFLEN,a2)
-
- lea (baudtable,pc),a0
- move.w (up_BaudRate,a1),d0 ;0-15
- add.w d0,d0
- moveq #0,d1
- move.w (a0,d0.w),d1
- move.l d1,(prefs_BAUD,a2)
-
- moveq #5,d1 ;5 bit word
- move.b (up_WordLen,a1),d0
- beq.b .WordLen ;up_WordLen=0
- addq.b #1,d1 ;6 bit word
- subq.b #1,d0
- beq.b .WordLen ;up_WordLen=1
- addq.b #1,d1 ;7 bit word
- subq.b #1,d0
- beq.b .WordLen ;up_WordLen=2
- addq.b #1,d1 ;8 bit word
- .WordLen:
- move.b d1,(prefs_READLEN,a2)
- move.b d1,(prefs_WRITELEN,a2)
-
- move.b (up_StopBits,a1),d0 ;0-1
- addq.b #1,d0
- move.b d0,(prefs_STOPBITS,a2)
-
- move.b (up_Parity,a1),d0
- cmp.b #4,d0 ;none?
- beq.b .SkipParity
- bset #SERB_PARTY_ON,(prefs_SERFLAGS,a2)
- cmp.b #2,d0
- bcc.b .MarkSpace
- bclr #SERB_PARTY_ODD,(prefs_SERFLAGS,a2) ;set to even
- tst.b d0
- bne.b .SkipParity
- bset #SERB_PARTY_ODD,(prefs_SERFLAGS,a2) ;set to odd
- bra.b .SkipParity
- .MarkSpace:
- bset #SEXTB_MSPON,(3+prefs_EXTFLAGS,a2)
- bclr #SEXTB_MARK,(3+prefs_EXTFLAGS,a2) ;set to space
- cmp.b #3,d0
- beq.b .SkipParity
- bset #SEXTB_MARK,(3+prefs_EXTFLAGS,a2)
-
- .SkipParity:
- move.b (up_Shake,a1),d0
- cmp.b #2,d0
- beq.b .SkipShake
- cmp.b #1,d0
- bne.b .SkipXon
- bclr #SERB_XDISABLED,(prefs_SERFLAGS,a2)
- bra.b .SkipShake
- .SkipXon:
- bset #SERB_7WIRE,(prefs_SERFLAGS,a2)
- .SkipShake:
- addq.l #1,d5
- add.w #serprefs_sizeof,a2
- dbra d7,.OuterLoop
-
- .EndInit:
- move.l a5,d0 ;no error (zero indicates error)
- ;MUST return device ptr
- PUTDEBUG 5,<'%s/Init: finished'>
- movem.l (sp)+,d1-d7/a0-a6
- rts
-
- MagicPortName: dc.b 'newser_prefs',0
- even
-
- MyUserState:
- ;(The one in 1.2/1.3 ROM is buggy)
- ;Enter with ExecBase in A6 and SSP in D0
- move.l (sp)+,d1
- move.l sp,usp
- movea.l d0,sp
- movea.l a5,a0
- lea (.L1,pc),a5
- jmp (_LVOSupervisor,a6)
- .L1: movea.l a0,a5
- move.l d1,(2,sp) ;store return address in stack frame
- andi.w #$DFFF,(sp) ;clear supervisor bit
- rte
-
- ;Enter with device ptr in a6.
-
- SetDefaultPrefs:
- movem.l d0/d1/a0/a1,-(sp)
- lea (prefs_unit0,a6),a1
- moveq #MD_NUMUNITS-1,d1
- 1$ move.w #serprefs_sizeof-1,d0
- lea (defaultprefs,pc),a0
- 2$ move.b (a0)+,(a1)+
- dbra d0,2$
- dbra d1,1$
- movem.l (sp)+,d0/d1/a0/a1
- rts
-
- NewVector:
- ;Enter with device ptr in a6
- ;exit with d0=0 if OK, else error!
-
- ;uses d0,a0,a1
-
- movem.l a0/a1,-(sp)
- move.l (VectorBase,a6),a1
- move.l (MyPreviousAutoVec,a6),d0
- cmp.l ($78,a1),d0
- bne.b .Error
-
- moveq #0,d0
- move.b (ScoreBoard,a6),d0
- lsl.l #2,d0
- lea (IntRoutines,pc),a0
- move.l (a0,d0.w),(MyPreviousAutoVec,a6)
- move.l (a0,d0.w),($78,a1)
- moveq #0,d0
- .End:
- movem.l (sp)+,a0/a1
- rts
- .Error:
- moveq #1,d0
- bra.b .End
-
- ;Here begins the system interface commands. When the user calls OpenDevice/
- ;CloseDevice/RemDevice, this eventually gets translated into a call to the
- ;following routines (Open/Close/Expunge). Exec has already put our device
- ;pointer in a6 for us.
- ;
- ;Open sets the IO_ERROR field on an error. If it was successful, we should
- ;also set up the IO_UNIT and LN_TYPE fields. exec takes care of setting up
- ;IO_DEVICE.
- ;
- ;NOTE: We must also copy the current prefs for this unit into the user's
- ;extended iorequest fields.
- ;
- ; Register Usage
- ; ==============
- ; d0 -- unitnum
- ; d1 -- flags
- ; a1 -- iob
- ; a6 -- Device ptr
-
- Open:
- addq.w #1,(LIB_OPENCNT,a6) ;Fake an opener for duration of call
- PUTDEBUG 20,<'%s/Open: called'>
- movem.l d2/a2-a4,-(sp)
- movea.l a1,a2 ;Save the iob
- cmp.l #MD_NUMUNITS,d0 ;See if the unit number is in range
- bcc Open_Range_Error ;Unit number out of range (BHS)
-
- ;Check to see if the corresponding chip is installed
- lea (Chip1present,a6),a4
- tst.b (a4,d0.w)
- beq Open_Range_Error
-
- move.l d0,d2 ;Save unit number
- lsl.l #2,d0 ;See if the unit is already initialized
- lea (md_Units,a6,d0.l),a4
- move.l (a4),d0
- bne.b Open_UnitOK
- ;Try to conjure up a unit
- bsr InitUnit ;scratch:a3 unitnum:d2 devpoint:a6
- move.l (a4),d0 ;See if it initialized OK
- beq.w Open_Error
- movea.l d0,a3
- bra.b Open_UnitOK1
-
- Open_UnitOK:
- movea.l d0,a3 ;Unit pointer in a3
- tst.b (Exclusive,a3) ;Check for an exclusive access violation
- beq Open_Error
- Open_UnitOK1:
- btst #SERB_SHARED,(IO_FLAGS,a2)
- seq (Exclusive,a3)
- movea.l (mdu_prefs,a3),a4 ;Set the "7WIRE" flag
-
- bclr #SERB_7WIRE,(prefs_SERFLAGS,a4)
- btst #SERB_7WIRE,(IO_SERFLAGS,a2)
- beq.b 2$
- bset #SERB_7WIRE,(prefs_SERFLAGS,a4)
-
- 2$: movea.l a2,a1 ;Copy the current internal prefs into the iorequest.
- bsr CopyPrefs
- move.l d0,(IO_UNIT,a2)
- addq.w #1,(LIB_OPENCNT,a6) ;Mark us as having another opener
- addq.w #1,(UNIT_OPENCNT,a3) ;Internal bookkeeping
- bclr #LIBB_DELEXP,(md_Flags,a6) ;Prevent delayed expunges
- clr.b (IO_ERROR,a2) ;no error
- move.b #NT_REPLYMSG,(LN_TYPE,a2) ;Mark IORequest as "complete"
- Open_End:
- subq.w #1,(LIB_OPENCNT,a6) ;End of expunge protection
- movem.l (sp)+,d2/a2-a4
- PUTDEBUG 30,<'%s/Open: Finished!'>
- rts
-
- Open_Range_Error:
- Open_Error:
- moveq #IOERR_OPENFAIL,d0
- move.b d0,(IO_ERROR,a2)
- move.l d0,(IO_DEVICE,a2) ;Trash IO_DEVICE on open failure
- PUTDEBUG 2,<'%s/Open: failed'>
- bra.b Open_End
-
- ;Copy prefs from our device struct to an IOrequest. Enter with IORequest
- ;in a1 and unit pointer in a3. All registers are preserved.
-
- CopyPrefs:
- movem.l d0/a1/a4,-(sp)
- movea.l (mdu_prefs,a3),a4
- lea (IO_CTLCHAR,a1),a1
- move.w #serprefs_sizeof-1,d0
- 1$: move.b (a4)+,(a1)+
- dbra d0,1$
- movem.l (sp)+,d0/a1/a4
- rts
-
- ;Copy prefs from an IOrequest to our device struct Enter with IORequest
- ;in a1 and unit pointer in a3. All registers are preserved.
-
- SetPrefs:
- movem.l d0/a1/a4,-(sp)
- movea.l (mdu_prefs,a3),a4
- lea (IO_CTLCHAR,a1),a1
- move.w #serprefs_sizeof-1,d0
- 1$: move.b (a1)+,(a4)+
- dbra d0,1$
- movem.l (sp)+,d0/a1/a4
- rts
-
- ;There are two different things that might be returned from the Close
- ;routine. If the device wishes to be unloaded, then Close must return
- ;the segment list (as given to Init). Otherwise close MUST return NULL.
- ; ( device:a6, iob:a1 )
-
- _Close:
- movem.l a2-a3,-(sp)
- PUTDEBUG 20,<'%s/Close: called'>
- movea.l a1,a2
- movea.l (IO_UNIT,a2),a3
- moveq #-1,d0
- move.l d0,(IO_UNIT,a2) ;We're closed...
- move.l d0,(IO_DEVICE,a2) ;Customers not welcome at this IORequest!
- subq.w #1,(UNIT_OPENCNT,a3) ;See if the unit is still in use
- bne.b Close_Device
- bsr ExpungeUnit
-
- Close_Device:
- moveq #0,d0
- subq.w #1,(LIB_OPENCNT,a6) ;Mark us as having one fewer openers
- bne.b Close_End ;See if there is anyone left with us open
- btst #LIBB_DELEXP,(md_Flags,a6) ;See if we have a delayed expunge pending
- beq.b Close_End
- bsr Expunge ;Do the expunge
- Close_End:
- movem.l (sp)+,a2-a3
- PUTDEBUG 20,<'%s/Close: Finished!'>
- rts ;MUST return either zero or the SegList!
-
- ;Expunge is called by the memory allocator when the system is low on
- ;memory.
- ;
- ;There are two different things that might be returned from the Expunge
- ;routine. If the device is no longer open then Expunge may return the
- ;segment list (as given to Init). Otherwise Expunge may set the
- ;delayed expunge flag and return NULL.
- ;
- ;One other important note: because Expunge is called from the memory
- ;allocator, it may NEVER Wait() or otherwise take long time to complete.
- ;
- ; A6 - library base (scratch)
- ; D0-D1/A0-A1 - scratch
-
- Expunge:
- PUTDEBUG 10,<'%s/Expunge: called'>
- movem.l d1/d2/a5/a6,-(sp) ;Save ALL modified registers
- movea.l a6,a5
- movea.l (md_SysLib,a5),a6
- tst.w (LIB_OPENCNT,a5) ;See if anyone has us open
- beq.b 1$
- bset #LIBB_DELEXP,(md_Flags,a5) ;Set the delayed expunge flag
- moveq #0,d0
- bra.b Expunge_End
- 1$:
-
- ;Important: If it's not possible to restore the old autovector, then don't
- ;expunge!!
- ;Restore old autovector if possible
- move.l (MyPreviousAutoVec,a5),a0
- move.l (VectorBase,a5),a1
- cmp.l ($78,a1),a0
- beq.b .ok
- moveq #0,d0
- bra.b Expunge_End
- .ok:
- move.l (OldVec,pc),($78,a1)
-
- move.l (md_SegList,a5),d2 ;Store our seglist in d2
- movea.l a5,a1 ;Unlink from device list
- SYS Remove ;Remove first (before FreeMem)
-
- movea.l a5,a1 ;Devicebase
- moveq #0,d0
- move.w (LIB_NEGSIZE,a5),d0
- suba.l d0,a1 ;Calculate base of functions
- add.w (LIB_POSSIZE,a5),d0 ;Calculate size of functions + data area
- SYS FreeMem
- move.l d2,d0 ;Set up our return value
- Expunge_End:
- movem.l (sp)+,d1/d2/a5/a6
- rts
-
- Null: moveq #0,d0 ;The "Null" function MUST return zero.
- rts
-
- ;This is the main unit initialization routine. It allocates memory for
- ;the device structure, calls SetUpUnit, then calls InitTask.
-
- ; ( d2:unit number, a3:scratch, a6:devptr )
-
- InitUnit:
- PUTDEBUG 30,<'%s/InitUnit: called'>
- movem.l d0/d1/a4/a2,-(sp)
- move.l d2,d1
- mulu.w #serprefs_sizeof,d1
- lea (prefs_unit0,a6),a4
- adda.l d1,a4
-
- ;Now A4 is a ptr to the prefs for this unit
-
- move.l #MyDevUnit_Sizeof,d0 ;Allocate unit memory
- move.l #MEMF_PUBLIC!MEMF_CLEAR,d1
- move.l a6,-(sp)
- movea.l (md_SysLib,a6),a6
- SYS AllocMem
- movea.l (sp)+,a6
- movea.l d0,a3
- tst.l d0
- bne continitunit1
-
- ;Couldn't init the unit (out of memory).
-
- ReturnVoid:
- move.l d2,d0 ;Unit number
- lsl.l #2,d0
- clr.l (md_Units,a6,d0.l) ;Set unit table
- movem.l (sp)+,d0/d1/a4/a2
- rts
-
- BadSetup:
- bsr KillTask
- bra.b ReturnVoid
-
- continitunit1:
- moveq #0,d0 ;Don't need to re-zero it
- movea.l a3,a2
- lea (mdu_Init,pc),a1
- move.l a6,-(sp)
- movea.l (md_SysLib,a6),a6
- SYS InitStruct
- movea.l (sp)+,a6
-
- move.l a5,-(sp) ;Look up DACIA base address
- lea (basetable,pc),a0
- moveq #0,d0
- move.b d2,d0
- lsl.l #2,d0
- movea.l (0,a0,d0.w),a5
- move.l a5,(daciabase,a3)
-
- move.b #$7f,(IER,a5) ;Disable DACIA interrupts
-
- bset d2,(ScoreBoard,a6)
- bsr SetUpUnit
- movea.l (sp)+,a5
- tst.l d0
- bne.b BadSetup
-
- bsr InitTask ;Set up the two tasks for this unit
- tst.l d0
- beq.b BadSetup
-
- ;Done with InitUnit - fill in the proper md_Unit field in the device struct
- ;and return.
- move.l d2,d0 ;Unit number
- lsl.l #2,d0
- move.l a3,(md_Units,a6,d0.l) ;Set unit table
- lea (Unit0,pc),a2
- move.l a3,(a2,d0.l)
- movem.l (sp)+,d0/d1/a4/a2
- PUTDEBUG 30,<'%s/InitUnit: finished! End of silence.'>
- rts
-
- ;This routine does the following:
- ;
- ;1. Allocate read buffer memory
- ;2. Initialize all the special MyDevUnit fields (but NOT the signals -
- ; they must be allocated in the task's context)
- ;3. Call InitDACIA [Initialize/set-up DACIA registers (for this unit).]
- ;4. Install an interrupt server.
- ;
- ;Returns failure code in d0 - zero if OK, -1 if out of memory, 1 if
- ;unable to open timer.device, 2 if invalid parm
- ;
- ;SetUpUnit(d2:unit number, a3:unit, a6:devptr)
- ;AND...ptr to prefs in A4
- ;uses d1,a0,a1,a2,a6
-
- SetUpUnit:
- PUTDEBUG 30,<'%s/SetUpUnit: called'>
- movem.l d1/a0/a1/a2,-(sp)
-
- move.l #65536,d0 ;buffer size
- move.l d0,(prefs_RBUFLEN,a4)
-
- move.l #MEMF_PUBLIC,d1
- EXEC AllocMem
- tst.l d0
- bne.b continitunit
- moveq #-1,d0 ;Failed to allocate input buffer memory - exit.
- movem.l (sp)+,d1/a0/a1/a2
- rts
-
- ;Initialize all the special MyDevUnit fields (but NOT the signals -
- ;they must be allocated in the task's context)
-
- continitunit:
- move.l d0,(StartBuf,a3)
- clr.l (HeadLong,a3)
- clr.l (TailLong,a3)
-
- move.l a4,(mdu_prefs,a3)
- move.l (SysBase).w,(mdu_SysLib,a3)
- lea (timerport+MP_MSGLIST,a3),a0
- NEWLIST a0 ;Init the unit's timer MsgPort's list
- move.b d2,(mdu_UnitNum,a3) ;Initialize unit number
- move.l a6,(mdu_Device,a3) ;Initialize device pointer
- move.b #$FF,(xstate,a3)
- move.b #$80,(frstate,a3)
- bset #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
-
- lea (timername,pc),a0 ;Open the timer device.
- moveq #UNIT_MICROHZ,d0
- lea (timeriorequest,a3),a1
- moveq #0,d1 ;no special flags
- move.l a6,-(sp)
- movea.l (md_SysLib,a6),a6
- SYS OpenDevice
- movea.l (sp)+,a6
- tst.l d0
- bne OpenTimerFailed
-
- ;Initialize/set-up DACIA registers (for this unit).
- ;(according to the prefs pointed to by a4)
-
- bsr InitDACIA
- tst.l d0
- bne InitDACIAfailed
-
- ;Install an interrupt server.
-
- bsr NewVector
- tst.l d0
- bne.b EndSetUpUnit
-
- moveq #0,d0 ;situation under control
- movem.l (sp)+,d1/a0/a1/a2
- PUTDEBUG 30,<'%s/SetUpUnit: Finished!'>
- rts
-
- InitDACIAfailed:
- moveq #2,d0
- bra.b EndSetUpUnit
-
- OpenTimerFailed:
- moveq #1,d0
- EndSetUpUnit:
- move.l d0,-(sp)
- move.l (prefs_RBUFLEN,a4),d0
- movea.l (StartBuf,a3),a1
- EXEC FreeMem
- move.l (sp)+,d0
- movem.l (sp)+,d1/a0/a1/a2
- rts
-
- ;****** end of SetUpUnit ******
-
- ;Initialize/set-up DACIA registers (for this unit).
- ;(according to the prefs pointed to by a4)
- ;d0.b will mirror CTR, d1.b will mirror FMR
- ;Returns error code in d0 - zero if successful.
- ;uses d1,d3,d5,a0
-
- InitDACIA:
- PUTDEBUG 30,<'%s/InitDACIA: Called.'>
- movem.l d1/d3/d5/a0,-(sp)
-
- ;"During power-on initialization, all readable registers should be read to
- ; assure that the status registers are initialized."
-
- move.b (ISR,a5),d0
- move.b (CSR,a5),d0
- move.b (RDR,a5),d0
-
- move.b (frstate,a3),d0 ;Set DTR* and RTS* low (assert)
- and.b #$FC,d0 ;Clear bits zero and one
- move.b d0,(frstate,a3)
- move.b d0,(FMR,a5)
-
- moveq #0,d0
- bset #6,d0 ;Always access ACR, never CDR
- move.b (frstate,a3),d1
-
- move.l (prefs_BAUD,a4),d3 ;First, set proper baud rate.
-
- ifne INFO_LEVEL ;If any debugging enabled at all
- move.l d3,-(sp)
- PUTDEBUG 150,<'%s/InitDACIA: %ldbps requested.'>
- addq.l #4,sp
- endc
-
- swap d3
- tst.w d3
- bne InvParm
- swap d3
-
- ;Test for (and allow) zero baud -- this makes Handshake happy
- ;(Not a bug in Handshake.) Old RKMs mentioned this behavior, but the
- ;latest RKMs do not. Argh!
-
- tst.l d3
- beq.b SkipBAUD
-
- lea (baudtable,pc),a0
- moveq #15,d5
- baudloop: cmp.w (a0)+,d3
- dbeq d5,baudloop
- bne InvParm
- not.b d5
- and.b #$0F,d5
- or.b d5,d0
-
- ifne INFO_LEVEL
- clr.l -(sp)
- move.b d0,(3,sp)
- PUTDEBUG 30,<'%s/InitDACIA: Baud rate = %lx'>
- addq.l #4,sp
- endc
-
- SkipBAUD:
- cmpi.b #1,(prefs_STOPBITS,a4) ;Next, set number of stop bits per character
- beq.b onestop
- bset #5,d0
- onestop:
- move.b d0,(CTR,a5)
-
- ;set data bits per character
- move.b (prefs_READLEN,a4),d3
- cmp.b (prefs_WRITELEN,a4),d3
- bne InvParm ;We don't support different read & write char lengths
- subq.b #5,d3
- bmi InvParm
- cmp.b #3,d3
- bhi InvParm
- lsl.b #5,d3
- and.b #$80,d1 ;bug fix (clear before OR)
- or.b d3,d1
-
- btst #SEXTB_MSPON,(prefs_EXTFLAGS+3,a4) ;Set parity
- beq.b EvenOdd
- bset #2,d1
- btst #SEXTB_MARK,(prefs_EXTFLAGS+3,a4)
- bne.b UseMark
- or.b #24,d1 ;Use space
- bra.b NoParity
-
- UseMark: or.b #16,d1
- bra.b NoParity
-
- EvenOdd: btst #SERB_PARTY_ON,(prefs_SERFLAGS,a4)
- beq.b NoParity
- bset #2,d1
-
- btst #SERB_PARTY_ODD,(prefs_SERFLAGS,a4)
- bne.b UseOdd
- or.b #8,d1
- UseOdd:
- NoParity:
-
- ifne INFO_LEVEL
- clr.l -(sp)
- move.b d1,(3,sp)
- PUTDEBUG 30,<'%s/InitDACIA: FMR = %lx'>
- addq.l #4,sp
- endc
-
- move.b d1,(frstate,a3)
- move.b d1,(FMR,a5)
- moveq #0,d0
- movem.l (sp)+,d1/d3/d5/a0
- PUTDEBUG 30,<'%s/InitDACIA: Finished!'>
- rts
-
- InvParm: PUTDEBUG 30,<'%s/InitDACIA: Invalid Parm!'>
- moveq #-1,d0
- movem.l (sp)+,d1/d3/d5/a0
- rts
-
- ;****** end of InitDACIA ******
-
- ;(this is a subroutine for InitUnit)
- ;This routine sets up the two tasks (one for reading, one for writing).
- ;Returns zero in d0.l if an error occured else a ptr to the unit.
- ;
- ;uses d1-d4 and a0-a5
-
- InitTask:
- PUTDEBUG 30,<'%s/InitTask: called.'>
- movem.l d1-d4/a0-a5,-(sp)
- lea (ReadTask_Begin,pc),a5 ;Set up the read task
- lea (mdu_rstack,a3),a0
- lea (mdu_rtcb,a3),a1
- movea.l a3,a2 ;Read message port
- bsr.b InitTaskStruct
-
- lea (WriteTask_Begin,pc),a5 ;Set up the write task
- lea (mdu_wstack,a3),a0
- lea (mdu_wtcb,a3),a1
- lea (mdu_wport,a3),a2
- bsr.b InitTaskStruct
-
- move.l a3,d0 ;Mark us as ready to go
- PUTDEBUG 30,<'%s/InitTask: ok'>
-
- ;Return zero in d0.l if an error occured, else a ptr to the unit
-
- movem.l (sp)+,d1-d4/a0-a5
- rts
-
- ;Start up the unit task. We do a trick here --we set his message port to
- ;PA_IGNORE until the new task has a change to set it up. We cannot go to
- ;sleep here: it would be very nasty if someone else tried to open the unit
- ;(exec's OpenDevice has done a Forbid() for us --we depend on this to become
- ;single threaded).
- ;
- ;Enter with:
- ;a0 - ptr to low end of stack
- ;a1 - ptr to tcb (task control block)
- ;a3 - unit pointer
- ;a5 - starting address of task
- ;a2 - ptr to a (uninitialized) message port
- ;
- ;uses a0-a3 and d0,d1
-
- InitTaskStruct:
- movem.l d0/d1/a0-a3,-(sp)
- move.l a0,(TC_SPLOWER,a1) ;Initialize the stack information
- lea (MYPROCSTACKSIZE,a0),a0 ;High end of stack
- move.l a0,(TC_SPUPPER,a1)
- move.l a3,-(a0) ;Argument - unit ptr (send on stack)
- move.l a0,(TC_SPREG,a1)
- move.l a1,(MP_SIGTASK,a2)
-
- ifge INFO_LEVEL-30
- move.l a1,-(sp)
- move.l a3,-(sp)
- PUTDEBUG 30,<'%s/InitUnit, unit= %lx, task=%lx'>
- addq.l #8,sp
- endc
-
- lea (MP_MSGLIST,a2),a0
- NEWLIST a0 ;Init the unit's MsgPort's list
- movea.l a5,a2 ;Startup the task
- move.w #-1,a3 ;generate address error
- ;if task ever "returns" (we RemTask() it
- ;to get rid of it...)
- moveq #0,d0
- PUTDEBUG 30,<'%s/About to add task'>
- move.l a6,-(sp)
- movea.l (md_SysLib,a6),a6
- SYS AddTask
- movea.l (sp)+,a6
- movem.l (sp)+,d0/d1/a0-a3
- rts
-
- ;Get rid of the unit's tasks. We know this is safe because the unit has an
- ;open count of zero, so it is 'guaranteed' not in use.
- ;
- ;Kill the two tasks
- ; ( a3:unitptr, a6:deviceptr )
- ;
- ;uses a0,a1 and d0-d2
-
- KillTask:
- movem.l a0/a1/d0-d2,-(sp)
- lea (mdu_rtcb,a3),a1
- move.l a6,-(sp)
- movea.l (md_SysLib,a6),a6
- SYS RemTask
- movea.l (sp)+,a6
-
- lea (mdu_wtcb,a3),a1
- move.l a6,-(sp)
- movea.l (md_SysLib,a6),a6
- SYS RemTask
- movea.l (sp)+,a6
-
- moveq #0,d2
- move.b (mdu_UnitNum,a3),d2 ;Save the unit number
- bsr FreeUnit ;Free the unit structure
- lsl.l #2,d2
- clr.l (md_Units,a6,d2.l) ;Clear out the unit vector in the device
- movem.l (sp)+,a0/a1/d0-d2
- rts
-
- ; ( a3:unitptr, a6:deviceptr )
- ;uses a0,a1,d0,d1
-
- FreeUnit:
- movem.l a0/a1/d0/d1,-(sp)
- movea.l a3,a1
- move.l #MyDevUnit_Sizeof,d0
- move.l a6,-(sp)
- movea.l (md_SysLib,a6),a6
- SYS FreeMem
- movea.l (sp)+,a6
- movem.l (sp)+,a0/a1/d0/d1
- rts
-
- ; ( a3:unitptr, a6:deviceptr )
- ;
- ;uses a0,a1,a5,d0-d2
-
- ExpungeUnit:
- movem.l a0/a1/a5/d0-d2,-(sp)
- PUTDEBUG 10,<'%s/ExpungeUnit: called'>
-
- movea.l (daciabase,a3),a5
- move.b #$7f,(IER,a5) ;shut off all interrupts
- move.b #$83,(FMR,a5) ;Deassert DTR* and RTS*
-
- bsr FreeResources
-
- lea (mdu_rtcb,a3),a1
- move.l a6,-(sp)
- movea.l (md_SysLib,a6),a6
- SYS RemTask
- movea.l (sp)+,a6
-
- lea (mdu_wtcb,a3),a1
- move.l a6,-(sp)
- movea.l (md_SysLib,a6),a6
- SYS RemTask
- movea.l (sp)+,a6
-
- moveq #0,d2
- move.b (mdu_UnitNum,a3),d2 ;Save the unit number
- bsr FreeUnit ;Free the unit structure.
-
- bclr d2,(ScoreBoard,a6)
- bsr NewVector
- lsl.l #2,d2
- clr.l (md_Units,a6,d2.l) ;Clear out the unit pointer in the device
-
- movem.l (sp)+,a0/a1/a5/d0-d2
- rts
-
- ;This routines frees up resources specific to this driver (the other
- ;resources are taken care of by the skeleton).
- ;Be careful with this routine, so as not to pull the rug out from
- ;underneath the driver...
- ;
- ;Enter with unit ptr in a3 and device ptr in a6
- ;
- ;uses a0,a1,a4,d0,d1
-
- FreeResources:
- PUTDEBUG 10,<'%s/FreeResources: called'>
- movem.l a0/a1/a4/d0/d1,-(sp)
- movea.l (StartBuf,a3),a1 ;Free input buffer memory
- movea.l (mdu_prefs,a3),a4
- move.l (prefs_RBUFLEN,a4),d0
- move.l a6,-(sp)
- movea.l (md_SysLib,a6),a6
- SYS FreeMem
- movea.l (sp)+,a6
-
- lea (timeriorequest,a3),a1 ;Close timer device
- move.l a6,-(sp)
- movea.l (md_SysLib,a6),a6
- SYS CloseDevice
- movea.l (sp)+,a6
- movem.l (sp)+,a0/a1/a4/d0/d1
- PUTDEBUG 10,<'%s/FreeResources: finished!'>
- rts
-
- ;Here begins the device functions
- ;
- ;Cmdtable is used to look up the address of a routine that will
- ;implement the device command.
-
- cmdtable:
- dc.w Invalid-cmdtable ;0 CMD_INVALID
- dc.w MyReset-cmdtable ;1 CMD_RESET
- dc.w Read-cmdtable ;2 CMD_READ
- dc.w Write-cmdtable ;3 CMD_WRITE
- dc.w Invalid-cmdtable ;4 CMD_UPDATE (update has no meaning here)
- dc.w MyClear-cmdtable ;5 CMD_CLEAR
- dc.w MyStop-cmdtable ;6 CMD_STOP
- dc.w Start-cmdtable ;7 CMD_START
- dc.w Flush-cmdtable ;8 CMD_FLUSH
- dc.w Query-cmdtable ;9 SDCMD_QUERY
- dc.w Break-cmdtable ;10 SDCMD_BREAK
- dc.w SetParams-cmdtable ;11 SDCMD_SETPARAMS
- dc.w Invalid-cmdtable ;12 not used
- dc.w Invalid-cmdtable ;13 not used
- dc.w Invalid-cmdtable ;14 not used
- dc.w Invalid-cmdtable ;15 not used
- dc.w SetControlLines-cmdtable ;16 - ASDG extension
-
- ;BeginIO starts all incoming io. The IO is either queued up for the
- ;unit task or processed immediately.
- ;
- ;BeginIO often is given the responsibility of making devices single
- ;threaded... so two tasks sending commands at the same time don't cause
- ;a problem. Once this has been done, the command is dispatched.
- ;
- ;Some IO requests do not need single threading. These can be performed
- ;immediatley.
- ;The immediate commands are Invalid, Reset, Stop, Start, Flush, Clear,
- ;Query, SetParams, and SetControlLines.
- ;
- ;IMPORTANT:
- ; The exec WaitIO() function uses the IORequest node type (LN_TYPE)
- ; as a flag. If set to NT_MESSAGE, it assumes the request is
- ; still pending and will wait. If set to NT_REPLYMSG, it assumes the
- ; request is finished. It's the responsibility of the device driver
- ; to set the node type to NT_MESSAGE before returning to the user.
- ;
- ;Notes: This routine looks at IO_COMMAND to determine which task
- ;to use. Break and Write requests go to the write
- ;task. Read requests (only) go to the read task.
- ;All other requests are performed immediately, i.e. within the caller's
- ;context.
- ;
- ;This routine uses a3,a4,a5 (and a0/a1/d0/d1, but those do not need to be
- ;preserved).
- ; ( iob: a1, device:a6 )
-
- ;************************** Start of BeginIO ***************************
-
- BeginIO:
-
- movem.l a3-a5,-(sp)
-
- ifge INFO_LEVEL-1
- bchg.b #1,($bfe001).l ;Blink the power LED
- endc
-
- ifge INFO_LEVEL-3
- clr.l -(sp)
- move.w (IO_COMMAND,a1),(2,sp) ;Get entire word
- PUTDEBUG 3,<'%s/BeginIO -- %ld'>
- addq.l #4,sp
- endc
-
- move.w (IO_COMMAND,a1),d0
- cmp.w #16,d0 ;command in range?
- bhi .NoCmd ;no, reject it.
-
- ;Do some initial set-up work
- andi.b #$f,(IO_FLAGS,a1) ;clear upper nibble
- move.b #NT_MESSAGE,(LN_TYPE,a1) ;So WaitIO() is guaranteed to work
- movea.l (IO_UNIT,a1),a3 ;Bookkeeping -> what unit to play with
- movea.l (mdu_prefs,a3),a4
- movea.l (daciabase,a3),a5
- clr.b (IO_ERROR,a1) ;No error so far
-
- cmp.w #CMD_READ,d0
- bne .NotRead
-
- ;If the task is busy reading, don't read in the caller's context!
- tst.l (ReadRequestPtr,a3)
- bne.b .ForgetIt
- lea (MP_MSGLIST,a3),a0 ;Read port - anything there?
- movea.l (a0),a0
- tst.l (a0)
- bne.b .ForgetIt
-
- ;Check whether there are enough characters in the buffer to do the read
- ;immediately.
-
- btst #SERB_RAD_BOOGIE,(prefs_SERFLAGS,a4) ;Check for RAD_BOOGIE
- beq.b .ForgetIt
- bsr GetBytesInReadBuf
- cmp.l (IO_LENGTH,a1),d0
- blo.b .ForgetIt
- bset #UNITB_READIMMEDIATE,(UNIT_FLAGS,a3)
- bne.b .ForgetIt
- bsr ReadImmediate
- bclr #UNITB_READIMMEDIATE,(UNIT_FLAGS,a3)
- bra .ReplyEnd
- .ForgetIt:
-
- ;Send message to read task
-
- move.l a3,a0
- bra .SendMessage
-
- .NotRead:
- cmp.w #CMD_WRITE,d0
- bne .NotWrite
-
- moveq #1,d0
- cmp.l (IO_LENGTH,a1),d0
- bne .QueueForWriteTask
-
- ;If the write task is busy writing, don't write in the caller's context!
- tst.l (WriteRequestPtr,a3)
- bne .QueueForWriteTask
- lea (mdu_wport+MP_MSGLIST,a3),a0 ;Write port - anything there?
- movea.l (a0),a0
- tst.l (a0)
- bne .QueueForWriteTask
-
- btst #SERB_7WIRE,(prefs_SERFLAGS,a4)
- bne.b .Handshake
- btst #CSRB_CTSL,(CSR,a5)
- bne .QueueForWriteTask
- .Handshake:
- tst.b (xstate,a3)
- beq .QueueForWriteTask
-
- Disable
- btst #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
- beq.b .NeedInt ;Enable, then QueueForWriteTask
- move.l (IO_DATA,a1),a0
- move.b (a0),(TDR,a5)
- bclr #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
- Enable
- bclr #UNITB_BREAKSENT,(UNIT_FLAGS,a3) ;for Query
- move.l d0,(IO_ACTUAL,a1)
- bra.b .ReplyEnd
-
- .NotWrite:
- cmp.w #SDCMD_BREAK,d0
- beq.b .QueueForWriteTask ;Handle just like a write request
-
- ;execute immediately
- lea (cmdtable,pc),a0
- add.w d0,d0
- add.w (a0,d0.w),a0
- jsr (a0)
-
- ;If the quick bit is set then we don't need to reply
-
- .ReplyEnd:
- btst #IOB_QUICK,(IO_FLAGS,a1)
- bne.b .End
- push a6
- move.l (4).w,a6
- SYS ReplyMsg
- pop a6
- .End: movem.l (sp)+,a3-a5
- rts
-
- .NeedInt:
- Enable
-
- .QueueForWriteTask:
- ;Send message to write task
-
- lea (mdu_wport,a3),a0
-
- .SendMessage:
- ;Send the IO request as a "message" to either the read or write task
- ;Enter with port address in A0 and IORequest in A1
-
- bclr #IOB_QUICK,(IO_FLAGS,a1) ;We did NOT complete this quickly
-
- ifge INFO_LEVEL-250
- move.l a1,-(sp)
- move.l a0,-(sp)
- PUTDEBUG 250,<'%s/PutMsg: Port=%lx Message=%lx'>
- addq.l #8,sp
- endc
-
- push a6
- movea.l (md_SysLib,a6),a6
- SYS PutMsg ;Port=a0, Message=a1
- pop a6
- bra .End
-
- .NoCmd:
- PUTDEBUG 200,<'%s/BeginIO_NoCmd!'>
- move.b #IOERR_NOCMD,(IO_ERROR,a1)
- bra .ReplyEnd
-
- ;************************* End of BeginIO ****************************
-
- ;Here begins the functions that implement the device commands
- ;all functions are called with:
- ; a1 -- a pointer to the io request block
- ; a3 -- a pointer to the unit
- ; a4 -- a pointer to prefs
- ; a5 -- a pointer to the unit hardware
- ; a6 -- a pointer to the device
- ;
- ;Commands that conflict with 68000 instructions have a "My" prepended to them.
-
- ;****************************** Read *****************************
-
- Read:
- movem.l d0-d6/a0/a2,-(sp)
-
- ;Try to do a quick read
- btst #SERB_RAD_BOOGIE,(prefs_SERFLAGS,a4) ;Check for RAD_BOOGIE
- beq.b .NoBoogie
-
- bsr GetBytesInReadBuf
- cmp.l (IO_LENGTH,a1),d0
- blo.b .NotEnoughDataInBuf
- bsr ReadImmediate
- bra .FinalEndRead
-
- .NoBoogie:
- .NotEnoughDataInBuf:
-
- moveq #0,d5 ;IO_ACTUAL
- move.l (IO_LENGTH,a1),d6
- movea.l (IO_DATA,a1),a2
-
- ifne INFO_LEVEL ;If any debugging enabled at all
- move.l d6,-(sp)
- PUTDEBUG 150,<'%s/Read entered -- %ld bytes requested.'>
- addq.l #4,sp
- endc
-
- bra .ReadEntry
-
- .ReadLoop:
- PUTDEBUG 150,<'%s/Read: Waiting for signal from interrupt code.'>
- move.l (readsig,a3),d0
- add.l (readabortsig,a3),d0
- bset #MDUB_WaitingForChar,(MDU_FLAGS,a3)
- EXEC Wait ;Wait for one or more bytes to come in
- and.l (readabortsig,a3),d0
- bne .ReadAbort
- .NoErrorAtAll:
- PUTDEBUG 150,<'%s/Read: One or more bytes came in.'>
-
- .ReadEntry:
- bsr GetBytesInReadBuf
-
- ifne INFO_LEVEL ;If any debugging enabled at all
- move.l d0,-(sp)
- PUTDEBUG 150,<'%s/Read: There are %ld bytes in the buffer.'>
- addq.l #4,sp
- endc
-
- tst.l d0
- beq .ReadLoop
- cmp.l d0,d6
- bls.b .AllDone ;Branch if d6 <= d0
- sub.l d0,d6
- bsr DumpReadBuf ;Dump d0 bytes of the read buffer into the user's buffer
- tst.l d0
- beq .ReadLoop
- bra.b .EndRead ;Go if TermArray caused early exit
-
- ;The number of bytes in the read buffer equals or exceeds the number of
- ;bytes the user wants.
-
- .AllDone:
- PUTDEBUG 150,<'%s/Read: All done.'>
- move.l d6,d0
- bsr DumpReadBuf ;Dump d0 bytes of the read buffer into the user's buffer
- .EndRead: PUTDEBUG 150,<'%s/Read: Finished!'>
-
- ; bclr #MDUB_V,(MDU_FLAGS,a3)
- ; beq.b NoOverflow
- ; move.b #SerErr_BufOverflow,(IO_ERROR,a1)
- ;NoOverflow:
-
- move.l d5,(IO_ACTUAL,a1)
- .FinalEndRead:
- movem.l (sp)+,d0-d6/a0/a2
- rts ;Done with read
-
- ;Something exceptional happened. An informative error code should be
- ;returned. first, check for error conditions... Note that the serial.device
- ;standard does not provide a way to inform the caller of simultaneous error
- ;conditions.
-
- .ReadAbort:
- PUTDEBUG 150,<'%s/readabort: Something exceptional happened.'>
- Disable
- move.b (ISRcopy,a3),d2
- move.b (CSRcopy,a3),d3
- clr.b (ISRcopy,a3)
- clr.b (CSRcopy,a3)
- Enable
- btst #ISRB_PAR,d2
- beq.b .notpar
-
- move.b #SerErr_ParityErr,(IO_ERROR,a1) ;parity error
- bra .EndRead
-
- .notpar: btst #1,d2 ;Check for frame err, overrun, & break
- beq .EndRead ;We infer that an abort has been issued
-
- ;This is a check for framing error....it might cause problems for
- ;some auto-baud algorithms, so it's commented out for this release.
-
- ; btst #CSRB_FE,d3 ;Probe further...
- ; beq.b noframe
-
- ; move.b #SerErr_LineErr,(IO_ERROR,a1) ;Framing Error
- ; bra endread
-
- .noframe: btst #CSRB_RBRK,d3
- beq .NoErrorAtAll
-
- ;Note that we ignore receive overrun errors. Since there is no error
- ;code for it, I assume this is what serial.device does too.
-
- move.b #SerErr_DetectedBreak,(IO_ERROR,a1) ;Break
- bra .EndRead
-
- ;****** Subroutines for the read routine ******
-
- GetBytesInReadBuf:
-
- ;Return with the number of bytes in the read buffer in d0
-
- move.l d1,-(sp)
-
- movem.l (HeadLong,a3),d0/d1 ;load HeadLong/TailLong
-
- ifne INFO_LEVEL ;If any debugging enabled at all
- move.l d0,-(sp)
- PUTDEBUG 150,<'%s/GetBytesInReadBuf: HeadLong=%ld'>
- addq.l #4,sp
- endc
-
- ifne INFO_LEVEL ;If any debugging enabled at all
- move.l d1,-(sp)
- PUTDEBUG 150,<'%s/GetBytesInReadBuf: TailLong=%ld'>
- addq.l #4,sp
- endc
-
- sub.l d0,d1
- bpl.b .skipadd
- add.l #65536,d1
- .skipadd:
- move.l d1,d0
-
- move.l (sp)+,d1
- rts
-
- ;Enter with number of bytes to read in d0
- ;Enter with a pointer to a dump buffer in a2
- ;the pointer in a2 is updated to reflect the current position
- ;
- ;This routine uses as scratch: d0,d5,d6,a2
- ;and updates the following: d5,a2
- ;Returns with D0=0 if all is OK, else a TermArray match was found.
-
- ;This is a subroutine used only by Read
-
- DumpReadBuf:
- movem.l d1/d6/d7/a0/a6,-(sp)
- move.l (HeadLong,a3),d1
- add.w d0,(Head,a3)
- move.l (StartBuf,a3),a0
-
- btst #SERB_RAD_BOOGIE,(prefs_SERFLAGS,a4)
- bne.b .Loop
-
- btst #SERB_EOFMODE,(IO_SERFLAGS,a1)
- beq.b .XLoop
-
- .EOFDump:
- moveq #7,d7
- lea (prefs_TERMARRAY,a4),a6
- move.b (a0,d1.l),d6 ;index MUST be long (sign extended)!
- btst #SERB_XDISABLED,(prefs_SERFLAGS,a4)
- bne.b .Skip
- bsr xcode
- .Skip: cmp.b (a6)+,d6
- dbcc d7,.Skip
- beq.b .TermRead
- move.b d6,(a2)+
- addq.l #1,d5
- addq.w #1,d1
- subq.l #1,d0
- bne.b .EOFDump
- bra.b .End
-
- .Loop:
- move.b (a0,d1.l),(a2)+ ;index MUST be long (sign extended)!
- addq.l #1,d5 ;add to IO_ACTUAL
- addq.w #1,d1 ;increment 16-bit head ptr
- subq.l #1,d0
- bne.b .Loop
- bra.b .End
-
- .XLoop:
- move.b (a0,d1.l),d6 ;index MUST be long (sign extended)!
- bsr.b xcode
- move.b d6,(a2)+
- addq.l #1,d5 ;add to IO_ACTUAL
- addq.w #1,d1 ;increment 16-bit head ptr
- subq.l #1,d0
- bne.b .XLoop
- bra.b .End
-
- .TermRead:
- moveq #-1,d0
- bra.b .End1
- .End:
- moveq #0,d0
- .End1:
- movem.l (sp)+,d1/d6/d7/a0/a6
- rts
-
- xcode:
-
- ;Check for xon/xoff
- ;Enter with current read character in d6.b
-
- ifne INFO_LEVEL
- move.l (prefs_CTLCHAR,a4),-(sp)
- PUTDEBUG 5,<'%s/XCODE: prefs_CTLCHAR = %lx'>
- addq.l #4,sp
- endc
-
- ifne INFO_LEVEL
- clr.l -(sp)
- move.b d6,(3,sp)
- PUTDEBUG 5,<'%s/XCODE: Current char = %lx'>
- addq.l #4,sp
- endc
-
- cmp.b (prefs_CTLCHAR,a4),d6 ;Xon check
- beq.b .XON
- cmp.b (prefs_CTLCHAR+1,a4),d6 ;Xoff check
- beq.b .XOFF
- rts
-
- .XON: PUTDEBUG 5,<'%s/XCODE: XON!'>
- tst.b (xstate,a3)
- bne.b .End ;If already on, don't signal!
- st (xstate,a3)
- movem.l d0/d1/a0/a1/a6,-(sp)
- move.l (xonsig,a3),d0
- lea (mdu_wtcb,a3),a1
- movea.l (mdu_SysLib,a3),a6
- SYS Signal
- movem.l (sp)+,d0/d1/a0/a1/a6
- .End: rts
-
- .XOFF: PUTDEBUG 5,<'%s/XCODE: XOFF!'>
- clr.b (xstate,a3)
- rts
-
- ReadImmediate:
-
- ;Fast read routine
- ;Requires boogie mode to be set and for there to be a sufficient number
- ;of bytes in the buffer to completely satisfy the request.
-
- ;Uses d0,d1,d2,d4,a0,a1,a2,a4,a6
-
- movem.l d0-d2/d4/a0-a2/a4/a6,-(sp)
- push a1
- move.l (HeadLong,a3),d2
- move.l (IO_LENGTH,a1),d4
- add.w d4,(Head,a3)
- move.l (IO_DATA,a1),a4
- move.l (StartBuf,a3),a2
- move.l (mdu_SysLib,a3),a6
-
- move.l #65536,d0
- sub.l d2,d0
- cmp.l d0,d4
- bls.b .UseIOLength
-
- ;Need 2 copy operations
- sub.l d0,d4
- move.l a4,a1
- add.l d0,a4
- lea (a2,d2.l),a0
- SYS CopyMem
- move.l d4,d0
- move.l a4,a1
- move.l a2,a0
- SYS CopyMem
- bra.b .ReadQuickEnd
-
- .UseIOLength:
- move.l d4,d0
- move.l a4,a1
- lea (a2,d2.l),a0
- SYS CopyMem
- .ReadQuickEnd:
- pop a1
- move.l (IO_LENGTH,a1),(IO_ACTUAL,a1)
- movem.l (sp)+,d0-d2/d4/a0-a2/a4/a6
- rts
-
- ;*************************** Write ******************************
-
- Write:
- comment |
- Potential problem: If a TDRE interrupt happens, and just at that instant
- (before the interrupt routine has time to kick into action) CTS is
- deasserted, the interrupt routine will miss the TDRE condition and the
- write routine will hang. This is unlikely, but possible. V2.10 adds
- a time-out feature to avoid this if it ever happens in real life.
- Testing the effectiveness of this solution is difficult, because I am
- solving a problem that has, to my knowledge, never occured. (hehe)
- |
-
- movem.l d0-d5/a0-a2,-(sp)
- push a1
- bclr #UNITB_BREAKSENT,(UNIT_FLAGS,a3) ;for Query
- btst #SERB_7WIRE,(prefs_SERFLAGS,a4)
- bne.b .Handshake
- btst #CSRB_CTSL,(CSR,a5)
- bne .NotConnected
-
- .Handshake:
- movea.l (IO_DATA,a1),a2
- move.l (IO_LENGTH,a1),d2
- beq .End
- bpl.b .CheckX
- move.l a2,a0 ;handle zero-terminated writes
- .L1: tst.b (a0)+
- bne.b .L1
- sub.l a2,a0
- move.l a0,d2
- .CheckX:
- tst.b (xstate,a3)
- bne .DoIt ;go if no XOFF
-
- PUTDEBUG 5,<'%s/Transmit: Waiting for XON!'>
- move.l (xonsig,a3),d0
- add.l (writeabortsig,a3),d0
- EXEC Wait ;Wait for an x-on signal before sending
- and.l (writeabortsig,a3),d0
- bne .Abort
- PUTDEBUG 5,<'%s/Transmit: Received XON!'>
- bra .CheckX
-
- .DoIt:
- move.l d2,d4
- Disable ;quite neccessary!
- btst #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
- beq.b .NeedInt
- bclr #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
- move.b (a2)+,(TDR,a5) ;If set, we can load up the transmit reg immediately
- subq.l #1,d4
- beq .DoneWriting ;does an Enable
-
- .NeedInt:
- move.l a2,(WriteBufferPtr,a3)
- move.l d4,(WriteCount,a3) ;GO!!!
- Enable
-
- lea (timeriorequest,a3),a1
- movea.l (MN_REPLYPORT,a1),a0
- moveq #0,d0
- move.b (MP_SIGBIT,a0),d0
- moveq #0,d3
- bset d0,d3
-
- .TopWaitBlock:
- moveq #0,d5 ;clear danger flag
- .WaitBlock:
- move.w #TR_ADDREQUEST,(IO_COMMAND,a1)
- clr.l (TV_SECS+IO_SIZE,a1)
- move.l #100000,(TV_MICRO+IO_SIZE,a1) ;100ms
- EXEC SendIO
-
- move.l d3,d0 ;timer signal
- add.l (writeabortsig,a3),d0
- add.l (tdresig,a3),d0
-
- ;Wait for the block write to finish
- EXEC Wait ;Wait for write to finish
- move.l d0,d1
- and.l (tdresig,a3),d1
- beq.b .NotTDRE
- EXEC AbortIO ;kill timer request
- EXEC WaitIO
-
- ; PUTDEBUG 150,<'%s/Transmit: Write block finished.'>
- .End:
- moveq #0,d0 ;value
- move.l d3,d1 ;mask
- EXEC SetSignal ;clear timer signal just in case
- pop a1
- move.l d2,(IO_ACTUAL,a1)
- movem.l (sp)+,d0-d5/a0-a2
- rts
- .NotTDRE:
- move.l d0,d1
- and.l (writeabortsig,a3),d1
- beq.b .CheckOut
-
- ;Abort signal
- EXEC AbortIO ;kill timer request
- EXEC WaitIO
- bra .Abort
-
- .CheckOut:
- ;If we end up here then a 100ms timeout has occured - so check a few
- ;things...
- EXEC WaitIO ;remove the message from the replyport
- move.l (WriteCount,a3),d0
- cmp.l d4,d0 ;compare with previous WriteCount value
- beq.b .Equal
- move.l d0,d4
- bra .TopWaitBlock
- .Equal:
- btst #CSRB_CTSL,(CSR,a5)
- bne .TopWaitBlock ;go if not asserted
- tst.l d5
- bne.b .Danger
- moveq #1,d5 ;set danger flag
- bra .WaitBlock
- .Danger:
-
- ;If we get here we know:
- ;1. Nothing has been outputted (no TDRE) in the last 100-200+ ms, and
- ;2. CTS is asserted (presumably at least 100ms -- we assume this)
- ;So, we assume that we got unlucky and missed a TDRE, and force a byte out:
-
- Disable
- bclr #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
- move.l (WriteBufferPtr,a3),a0
- move.b (a0)+,(TDR,a5)
- move.l a0,(WriteBufferPtr,a3)
- subq.l #1,(WriteCount,a3)
- beq.b .DoneWriting
- Enable
- bra .TopWaitBlock
-
- .DoneWriting:
- Enable
- bra .End
- .NotConnected:
- move.b #SerErr_LineErr,(IO_ERROR,a1)
- bra .End
- .Abort:
- sub.l (WriteCount,a3),d2
- clr.l (WriteCount,a3)
- bra .End
-
- ;******* end of write routine *******
-
- Break:
- movem.l d0-d2/a0/a1,-(sp)
- PUTDEBUG 5,<'%s/Break: called'>
- move.b #2,(ACR,a5) ;start break
- bset #UNITB_BREAKSENT,(UNIT_FLAGS,a3)
- lea (timeriorequest,a3),a1
- move.w #TR_ADDREQUEST,(IO_COMMAND,a1)
- clr.l (TV_SECS+IO_SIZE,a1)
- move.l (prefs_BRKTIME,a4),d0
- ori.b #$FF,d0 ;To avoid the V33/V34 timer bug
-
- ifne INFO_LEVEL ;If any debugging enabled at all
- move.l d0,-(sp)
- PUTDEBUG 5,<'%s/Break: TV_MICRO=%ld'>
- addq.l #4,sp
- endc
-
- move.l d0,(TV_MICRO+IO_SIZE,a1)
- movea.l (MN_REPLYPORT,a1),a0
- moveq #0,d2
- move.b (MP_SIGBIT,a0),d2
- EXEC SendIO
- moveq #0,d0
- bset d2,d0
- add.l (writeabortsig,a3),d0
-
- PUTDEBUG 5,<'%s/Break: Waiting...'>
-
- EXEC Wait
- and.l (writeabortsig,a3),d0
- beq.b .BreakOK
-
- PUTDEBUG 5,<'%s/Break: Aborted!'>
-
- EXEC AbortIO ;The break was aborted. Clean up.
- .BreakOK:
- EXEC WaitIO
- moveq #0,d0 ;value
- moveq #0,d1
- bset d2,d1 ;mask
- EXEC SetSignal ;clear timer signal bit just in case
- move.b #0,(ACR,a5) ;stop the break
-
- PUTDEBUG 5,<'%s/Break: Finished!'>
- movem.l (sp)+,d0-d2/a0/a1
- rts
-
- ;AbortIO() is a REQUEST to "hurry up" processing of an IORequest.
- ;If the IORequest was already complete, nothing happens (if an IORequest
- ;is quick or LN_TYPE=NT_REPLYMSG, the IORequest is complete).
- ;The message must be replied with ReplyMsg(), as normal.
- ;
- ;Note that AbortIO is called directly, not via BeginIO.
- ;
- ;If sucessful, AbortIO returns IOERR_ABORTED in IO_ERROR and zero in D0
-
- AbortIO:
- PUTDEBUG 5,<'%s/AbortIO: called'>
- Forbid
- movem.l d1/a0/a1/a3,-(sp)
- movea.l (IO_UNIT,a1),a3
- move.b #IOERR_ABORTED,(IO_ERROR,a1) ;We always say we succeed(ed)
- cmpi.b #NT_REPLYMSG,(LN_TYPE,a1) ;Already complete?
- beq.b .End
- btst #IOB_QUICK,(IO_FLAGS,a1)
- bne.b .End
-
- ;Check to see whether or not the IORequest is being processed
-
- cmpi.w #CMD_READ,(IO_COMMAND,a1)
- bne.b .NotRead
- cmp.l (ReadRequestPtr,a3),a1
- bne.b .NotActive
- move.l (readabortsig,a3),d0
- lea (mdu_rtcb,a3),a1
- .Signal: EXEC Signal
- bra.b .End
- .NotRead:
- cmpi.w #CMD_WRITE,(IO_COMMAND,a1)
- bne.b .NotWrite
- .Write: cmp.l (WriteRequestPtr,a3),a1
- bne.b .NotActive
- move.l (writeabortsig,a3),d0
- lea (mdu_wtcb,a3),a1
- bra.b .Signal
- .NotWrite:
- cmpi.w #SDCMD_BREAK,(IO_COMMAND,a1)
- beq.b .Write
- bra.b .End
-
- .NotActive:
- ;Set ignore bit in the IORequest
- bset #ioflagsB_Ignore,(IO_FLAGS,a1)
-
- .End: Permit
- movem.l (sp)+,d1/a0/a1/a3
- moveq #0,d0 ;error code (always successful)
- PUTDEBUG 5,<'%s/AbortIO: Finished!'>
- rts
-
- ;**************** End of AbortIO *****************
-
- Invalid:
- move.b #IOERR_NOCMD,(IO_ERROR,a1)
- rts
-
- ;Clear invalidates all internal buffers.
- ;
- ; a1 -- a pointer to the io request block
- ; a3 -- a pointer to the unit
- ; a4 -- a pointer to prefs
- ; a5 -- a pointer to the unit hardware
- ; a6 -- a pointer to the device
-
- MyClear:
- movem.l d0/d1,-(sp)
- moveq #0,d0
- moveq #0,d1
- movem.l d0/d1,(HeadLong,a3)
- movem.l (sp)+,d0/d1
- rts
-
- ; a1 -- a pointer to the io request block
- ; a3 -- a pointer to the unit
- ; a4 -- a pointer to prefs
- ; a5 -- a pointer to the unit hardware
- ; a6 -- a pointer to the device
-
- MyReset:
- movem.l d0/d7/a1,-(sp)
-
- PUTDEBUG 30,<'%s/MyReset: called'>
- Forbid
- move.b (IERstate,a3),d7
- clr.b (IERstate,a3)
- move.b #$7f,(IER,a5) ;Disable ACIA interrupts
- bsr Flush ;Flush pending requests
-
- ;Abort current IO, if any IO is indeed occuring
-
- move.l a1,-(sp)
-
- movea.l (WriteRequestPtr,a3),a1
- move.l a1,d0
- beq.b .WriteNotActive
- bsr AbortIO
-
- .WriteNotActive:
- movea.l (ReadRequestPtr,a3),a1
- move.l a1,d0
- beq.b .NothingActive
- bsr AbortIO
-
- .NothingActive:
- movea.l (sp)+,a1
- bsr SetDefaultPrefs
- bsr CopyPrefs
- bsr FreeResources
- bsr SetUpUnit
-
- tst.l d0 ;Check for a possible error condition
- bmi.b .OutOfMem
- subq.l #1,d0
- beq.b .TimerError
- subq.l #1,d0
- beq.b .ParamError
-
- move.b d7,(IERstate,a3) ;Enable DACIA interrupts again
- bset #7,d7
- move.b d7,(IER,a5)
- Permit
- clr.l (IO_ACTUAL,a1)
- PUTDEBUG 30,<'%s/MyReset: Finished!'>
- .ResetEnd:
- movem.l (sp)+,d0/d7/a1
- rts
-
- .ParamError:
- move.b #SerErr_InvParam,(IO_ERROR,a1)
- bra.b .MyResetFailed
-
- .TimerError:
- move.b #SerErr_TimerErr,(IO_ERROR,a1)
- bra.b .MyResetFailed
-
- .OutOfMem:
- move.b #SerErr_BufErr,(IO_ERROR,a1)
- .MyResetFailed:
- Permit
- clr.l (IO_ACTUAL,a1)
- PUTDEBUG 30,<'%s/MyReset: Error!'>
- bra.b .ResetEnd
-
- ; a1 -- a pointer to the io request block
- ; a3 -- a pointer to the unit
- ; a4 -- a pointer to prefs
- ; a5 -- a pointer to the unit hardware
- ; a6 -- a pointer to the device
- ;
- ;Return number of chars in buffer in IO_ACTUAL
- ;Fill in IO_STATUS
-
- Query:
- movem.l d0-d1,-(sp)
- ; PUTDEBUG 30,<'%s/Query: called.'>
-
- bsr GetBytesInReadBuf
- move.l d0,(IO_ACTUAL,a1)
-
- ifne INFO_LEVEL ;If any debugging enabled at all
- move.l d0,-(sp)
- ; PUTDEBUG 30,<'%s/Query: %ld bytes in buf.'>
- move.l (sp)+,d0
- endc
-
- moveq #0,d0 ;d0 will mirror IO_STATUS
- move.b (CSR,a5),d1
- btst #0,d1
- beq.b Q1
- bset #6,d0
- Q1: btst #1,d0
- beq.b Q2
- bset #7,d0
- Q2: btst #3,d1
- beq.b Q3
- bset #3,d0
- Q3: btst #4,d1
- beq.b Q4
- bset #5,d0 ;carrier detect
- Q4: btst #5,d1
- beq.b Q5
- bset #4,d0
- Q5: btst #UNITB_BREAKSENT,(UNIT_FLAGS,a3)
- beq.b NB
- bset #9,d0
- NB: btst #2,d1
- beq.b NRB
- bset #10,d0
- NRB: tst.b (xstate,a3)
- bne.b xIsOn
- bset #11,d0
- xIsOn: move.w d0,(IO_STATUS,a1)
- movem.l (sp)+,d0-d1
- rts
-
- ; a1 -- a pointer to the io request block
- ; a3 -- a pointer to the unit
- ; a4 -- a pointer to prefs
- ; a5 -- a pointer to the unit hardware
- ; a6 -- a pointer to the device
-
- SetParams:
- movem.l d0/a0/a2,-(sp)
- bclr #SERB_XDISABLED,(prefs_SERFLAGS,a4) ;enable
- btst #SERB_XDISABLED,(IO_SERFLAGS,a1)
- beq.b .NotDisabled
- bset #SERB_XDISABLED,(prefs_SERFLAGS,a4)
- st (xstate,a3) ;set to X-ON state
- .NotDisabled:
-
- ;Now check to see whether the device is busy, i.e. any current or pending requests.
-
- Forbid
- tst.l (ReadRequestPtr,a3)
- bne .DevBusy
- tst.l (WriteRequestPtr,a3)
- bne .DevBusy
- lea (MP_MSGLIST,a3),a0 ;Read port - anything there?
- movea.l (a0),a2
- tst.l (a2)
- bne.b .DevBusy
- lea (mdu_wport+MP_MSGLIST,a3),a0 ;Write port - anything there?
- movea.l (a0),a2
- tst.l (a2)
- bne.b .DevBusy
-
- ;Ok, the device is not busy. Set all params.
-
- bsr SetPrefs ;First copy the data
- move.l #65536,(prefs_RBUFLEN,a4)
-
- ;---> This section of code was supposed to increase compatibility, but
- ;---> it actually decreases it!! The autodocs fail me again....
- ;If boogie is set, it implies a few other things...(NOT!!!!)
- ; btst #SERB_RAD_BOOGIE,(IO_SERFLAGS,a1) ;Check for RAD_BOOGIE
- ; beq.b .SkipBoogie
- ; bclr #SEXTB_MSPON,(prefs_EXTFLAGS+3,a4)
- ; bclr #SERB_PARTY_ON,(prefs_SERFLAGS,a4)
- ; bset #SERB_XDISABLED,(prefs_SERFLAGS,a4)
- ; move.b #8,(prefs_READLEN,a4)
- ; move.b #8,(prefs_WRITELEN,a4)
- ; bra.b .SkipNext
- ;.SkipBoogie:
-
-
- ;The boogie flag is not set...but maybe it should be...
- ;Note that this logic is depended on in the Read routine
- btst #SERB_XDISABLED,(prefs_SERFLAGS,a4)
- beq.b .nochance
- btst #SERB_EOFMODE,(prefs_SERFLAGS,a4)
- bne.b .nochance
- bset #SERB_RAD_BOOGIE,(prefs_SERFLAGS,a4) ;Set RAD_BOOGIE !
-
- .nochance:
- .SkipNext:
- bsr InitDACIA ;Then set up the chip
- tst.l d0
- bne.b .Invalid
-
- .End: Permit
- movem.l (sp)+,d0/a0/a2
- rts
-
- .Invalid: move.b #SerErr_InvParam,(IO_ERROR,a1)
- bra.b .End
-
- .DevBusy: move.b #SerErr_DevBusy,(IO_ERROR,a1)
- bra.b .End
-
- SetControlLines:
-
- comment |
-
- This routine is an extension specified by ASDG for their Dual Serial
- Board. It allows application control of RTS and DTR. It works like this:
-
- IO_COMMAND = 16
-
- IO_OFFSET = mask
- IO_LENGTH = value
- Bit 0 = RTS
- Bit 1 = DTR
- |
-
- movem.l d0-d2,-(sp)
- Forbid
- move.b (frstate,a3),d0
- move.l (IO_LENGTH,a1),d1 ;state
- move.l (IO_OFFSET,a1),d2 ;mask
- and.b d2,d1
- not.b d2
- and.b d2,d0 ;clear
- or.b d1,d0 ;set
- move.b d0,(frstate,a3)
- move.b d0,(FMR,a5)
- Permit
- movem.l (sp)+,d0-d2
- rts
-
- ;The Stop command stop all future io requests from being processed until a
- ;Start command is received. The Stop command is NOT stackable: e.g. no matter
- ;how many stops have been issued, it only takes one Start to restart
- ;processing.
-
- MyStop:
- PUTDEBUG 30,<'%s/MyStop: called'>
- bset #MDUB_STOPPED,(MDU_FLAGS,a3)
- rts
-
- Start:
-
- ;[A3=unit A6=device]
-
- movem.l d0-d1/a0-a2,-(sp)
- PUTDEBUG 30,<'%s/Start: called'>
- movea.l a1,a2
-
- ;Turn processing back on
- bclr #MDUB_STOPPED,(MDU_FLAGS,a3)
-
- ;Kick the tasks to start them moving
-
- move.b (MP_SIGBIT,a3),d1 ;First the read task...
- moveq #0,d0
- bset d1,d0 ;Prepared signal mask
- movea.l (MP_SIGTASK,a3),a1 ;FIXED: marco-task to signal
- move.l a6,-(sp)
- movea.l (md_SysLib,a6),a6
- SYS Signal ;FIXED: marco-a6 not a3
- movea.l (sp)+,a6
-
- movea.l a2,a1 ;Then the write task
- lea (mdu_wport,a3),a0
- move.b (MP_SIGBIT,a0),d1
- moveq #0,d0
- bset d1,d0 ;Prepared signal mask
- movea.l (MP_SIGTASK,a0),a1 ;FIXED: marco-task to signal
- move.l a6,-(sp)
- movea.l (md_SysLib,a6),a6
- SYS Signal ;FIXED: marco-a6 not a3
- movea.l (sp)+,a6
- PUTDEBUG 30,<'%s/Start: Finished!'>
- movem.l (sp)+,d0-d1/a0-a2
- rts
-
- ;Flush pulls all I/O requests off the queue and sends them back. We must be
- ;careful not to destroy work in progress, and also that we do not let some io
- ;requests slip by.
-
- Flush:
- movem.l d0-d1/a0/a1/a6,-(sp)
- PUTDEBUG 30,<'%s/Flush: called'>
- movea.l (md_SysLib,a6),a6
- SYS Forbid
- ReadFlush_Loop:
- movea.l a3,a0
- SYS GetMsg ;Steal messages from task's port
- tst.l d0
- beq.b WriteFlush_Loop
-
- movea.l d0,a1
- move.b #IOERR_ABORTED,(IO_ERROR,a1)
- SYS ReplyMsg
- bra.b ReadFlush_Loop
-
- WriteFlush_Loop:
- lea (mdu_wport,a3),a0
- SYS GetMsg ;Steal messages from task's port
- tst.l d0
- beq.b Flush_End
-
- movea.l d0,a1
- move.b #IOERR_ABORTED,(IO_ERROR,a1)
- SYS ReplyMsg
- bra.b WriteFlush_Loop
-
- Flush_End:
- SYS Permit
- PUTDEBUG 30,<'%s/Flush: Finished!'>
- movem.l (sp)+,d0-d1/a0/a1/a6
- rts
-
- ;Here begins the task related routines
- ;
- ; Register Usage
- ; ==============
- ; a2 -- device pointer
- ; a3 -- unit pointer
- ; a4 -- prefs pointer
- ; a5 -- hardware pointer
- ; a6 -- syslib pointer
- ;----------------------------------------------------------------------
- ;
- ;Note: Signals must be allocated within this (the task's) context!
- ;The task is responsible for enabling the right DACIA interrupts...AFTER
- ;it has done its setup (like allocating signals).
- ;
- ;NOTE: We actually have two tasks, each with their own separate
- ; code (but shared data). First comes the read task...:
-
- ReadTask_Begin:
- PUTDEBUG 35,<'%s/ReadTask_Begin'>
- movea.l (4).w,a6
-
- ;Grab the arguments passed down from our parent
-
- movea.l (4,sp),a3 ;Unit pointer
- move.l (mdu_prefs,a3),a4
- movea.l (daciabase,a3),a5
-
- lea (readsig,a3),a2
- moveq #1,d6 ;Number of signals to allocate-1
- ReadSigLoop:
- moveq #-1,d0 ;-1 is any signal at all
- SYS AllocSignal ;Allocate signals for I/O interrupts
- moveq #0,d7 ;Convert bit number signal mask
- bset d0,d7
- move.l d7,(a2)+ ;Save in unit structure
- dbra d6,ReadSigLoop
-
- movea.l (mdu_Device,a3),a2 ;Point to device structure
-
- moveq #-1,d0 ;-1 is any signal at all
- SYS AllocSignal ;Allocate a signal
- move.b d0,(MP_SIGBIT,a3)
- move.b #PA_SIGNAL,(MP_FLAGS,a3) ;Make message port "live"
-
- ifge INFO_LEVEL-40
- move.l ($114,a6),-(sp)
- move.l (mdu_Device,a3),-(sp)
- move.l a3,-(sp)
- move.l d0,-(sp)
- PUTDEBUG 40,<'%s/ReadTask -- Signal=%ld, Unit=%lx Device=%lx Task=%lx'>
- adda.l #4*4,sp
- endc
-
- ;Enable read-related ACIA interrupts
-
- ori.b #READINTMASK,(IERstate,a3)
- move.b #READINT,(IER,a5)
- bra ReadTask_NextMessage
-
- ;OK, kids, we are done with initialization. We now can start the main loop
- ;of the driver. It goes like this. Because we had the port marked PA_IGNORE
- ;for a while (in InitUnit) we jump to the getmsg code on entry. (The first
- ;message will probably be posted BEFORE our task gets a chance to run).
- ; wait for a message
- ; lock the device
- ; get a message. If no message, unlock device and loop
- ; dispatch the message
- ; loop back to get a message
-
- ;Main loop: wait for a new message
-
- ReadTask_PermitMainLoop:
- Permit
- ReadTask_MainLoop:
- PUTDEBUG 75,<'%s/ReadTask ++Sleep'>
- move.l a3,a0
- SYS WaitPort
- ifge INFO_LEVEL-5
- bchg.b #1,($bfe001).l ;Blink the power LED
- endc
-
- PUTDEBUG 75,<'%s/ReadTask ++Wakeup'>
-
- btst #MDUB_STOPPED,(MDU_FLAGS,a3) ;See if we are stopped
- bne.b ReadTask_MainLoop ;Device is stopped, ignore messages
-
- ReadTask_NextMessage:
- movea.l a3,a0
- Forbid
- SYS GetMsg ;Get the next request
- PUTDEBUG 1,<'%s/ReadTask GotMsg'>
- tst.l d0
- beq ReadTask_PermitMainLoop ;no message?
-
- movea.l d0,a1 ;Do this request
- exg a2,a6 ;Put device ptr in right place
-
- btst #ioflagsB_Ignore,(IO_FLAGS,a1)
- bne.b Readignorecmd
- move.l a1,(ReadRequestPtr,a3)
- Permit
- bsr Read ;Do it!
- clr.l (ReadRequestPtr,a3)
- EXEC ReplyMsg
-
- ;No longer active - abort has stopped sending signals. Now we can
- ;(and should) clear the abort signal.
-
- moveq #0,d0
- move.l (readabortsig,a3),d1
- EXEC SetSignal
- bra.b Readconttl
-
- Readignorecmd:
- Permit
- clr.l (IO_ACTUAL,a1)
- EXEC ReplyMsg
- Readconttl:
- exg a2,a6 ;Get ExecBase back in a6
- bra ReadTask_NextMessage
-
- ;**** End of read task code ****
-
- ;**** Beginning of write task code ****
-
- ; Register Usage
- ; ==============
- ; a2 -- device pointer
- ; a3 -- unit pointer
- ; a4 -- prefs pointer
- ; a5 -- hardware pointer
- ; a6 -- syslib pointer
-
- WriteTask_Begin:
- PUTDEBUG 35,<'%s/WriteTask_Begin'>
- movea.l (SysBase).w,a6
-
- ;Grab the arguments passed down from our parent
-
- movea.l (4,sp),a3 ;Unit pointer
- move.l (mdu_prefs,a3),a4
- movea.l (daciabase,a3),a5
-
- lea (tdresig,a3),a2
- moveq #2,d6 ;Number of signals to allocate-1
- WriteSigLoop:
- moveq #-1,d0 ;-1 is any signal at all
- SYS AllocSignal ;Allocate signals for I/O interrupts
- moveq #0,d7 ;Convert bit number signal mask
- bset d0,d7
- move.l d7,(a2)+ ;Save in unit structure
- dbra d6,WriteSigLoop
-
- ;Allocate a signal for the timer message port
-
- moveq #-1,d0 ;-1 is any signal at all
- SYS AllocSignal
- lea (timerport,a3),a2
- move.b d0,(MP_SIGBIT,a2)
- move.l a2,(timeriorequest+MN_REPLYPORT,a3)
- suba.l a1,a1
- SYS FindTask
- move.l d0,(MP_SIGTASK,a2)
- move.b #PA_SIGNAL,(MP_FLAGS,a2) ;Make message port "live"
-
- movea.l (mdu_Device,a3),a2 ;Point to device structure
-
- ;Allocate a signal for the cmd message port
-
- moveq #-1,d0 ;-1 is any signal at all
- SYS AllocSignal
- move.b d0,(mdu_wport+MP_SIGBIT,a3)
- move.b #PA_SIGNAL,(mdu_wport+MP_FLAGS,a3) ;Make message port "live"
-
- ifge INFO_LEVEL-40
- move.l (ThisTask,a6),-(sp)
- move.l a5,-(sp)
- move.l a3,-(sp)
- move.l d0,-(sp)
- PUTDEBUG 40,<'%s/WriteTask -- Signal=%ld, Unit=%lx Device=%lx Task=%lx'>
- adda.l #4*4,sp
- endc
-
- ;Enable write-related ACIA interrupts
-
- ori.b #WRITEINTMASK,(IERstate,a3)
- move.b #WRITEINT,(IER,a5)
- bra WriteTask_NextMessage
-
- ;Main loop: wait for a new message
-
- WriteTask_PermitMainLoop:
- Permit
- WriteTask_MainLoop:
- PUTDEBUG 75,<'%s/WriteTask ++Sleep'>
-
- lea (mdu_wport,a3),a0
- SYS WaitPort
-
- ifge INFO_LEVEL-5
- bchg.b #1,($bfe001).l ;Blink the power LED
- endc
- PUTDEBUG 75,<'%s/WriteTask ++Wakeup'>
-
- btst #MDUB_STOPPED,(MDU_FLAGS,a3) ;See if we are stopped
- bne ReadTask_MainLoop ;Device is stopped, ignore messages
-
- WriteTask_NextMessage:
- lea (mdu_wport,a3),a0
- Forbid
- SYS GetMsg ;Get the next request
- PUTDEBUG 1,<'%s/WriteTask GotMsg'>
- tst.l d0
- beq WriteTask_PermitMainLoop ;No message?
-
- movea.l d0,a1 ;Do this request
- exg a2,a6 ;Put device ptr in right place
-
- btst #ioflagsB_Ignore,(IO_FLAGS,a1)
- bne.b Writeignorecmd
- move.l a1,(WriteRequestPtr,a3)
- Permit
- cmp.w #CMD_WRITE,(IO_COMMAND,a1)
- bne.b .NotWrite
- bsr Write
- bra.b .Continue
- .NotWrite:
- bsr Break
- .Continue:
- clr.l (WriteRequestPtr,a3)
- EXEC ReplyMsg
-
- ;No longer active - abort has stopped sending signals. Now we can
- ;(and should) clear the abort signal.
-
- moveq #0,d0
- move.l (writeabortsig,a3),d1
- EXEC SetSignal
- bra.b Writeconttl
-
- Writeignorecmd:
- Permit
- clr.l (IO_ACTUAL,a1)
- EXEC ReplyMsg
- Writeconttl:
- exg a2,a6 ; get syslib back in a6
- bra WriteTask_NextMessage
-
- ;********** end of write task code ***********
-
- ;Initialize the device
-
- mdu_Init:
- ;Initialize read task message port/tcb
- INITBYTE MP_FLAGS,PA_IGNORE ;Unit starts with read message port
- INITBYTE LN_TYPE,NT_MSGPORT
- INITLONG LN_NAME,myName
- INITLONG mdu_rtcb+LN_NAME,myName
- INITBYTE mdu_rtcb+LN_TYPE,NT_TASK
- INITBYTE mdu_rtcb+LN_PRI,127
-
- ;Initialize write task message port/tcb
-
- INITBYTE mdu_wport+MP_FLAGS,PA_IGNORE ;Write message port
- INITBYTE mdu_wport+LN_TYPE,NT_MSGPORT
- INITLONG mdu_wport+LN_NAME,myName
- INITLONG mdu_wtcb+LN_NAME,myName
- INITBYTE mdu_wtcb+LN_TYPE,NT_TASK
- INITBYTE mdu_wtcb+LN_PRI,126
-
- ;Initialize timer message port
-
- INITBYTE timerport+MP_FLAGS,PA_IGNORE ;Timer message port
- INITBYTE timerport+LN_TYPE,NT_MSGPORT
- INITLONG timerport+LN_NAME,myName
-
- dc.w 0
-
- ;******************** Interrupt code *********************************
-
- ;Notes:
-
- ;In this version of the driver we use a single interrupt routine for all
- ;units, and that routine bypasses the usual Exec conventions. Normally
- ;this would be bad, but the need for speed certainly warrents it in this
- ;case.
-
- ;This is the interrupt routine. It serves three purposes:
- ;1. Read in a byte if available, store it, and signal the read task
- ;2. Check for TDRE-empty condition and signal write task
- ;3. Check for an exceptional condition and signal read task
-
- ;uses d0,d7,a0,a3,a5
-
- DoInt macro
- movem.l d0/d7/a0/a3/a5,-(sp)
-
- ifge \1-1
- move.l (Unit3,pc),a3
- move.l (daciabase,a3),a5
- move.b (ISR,a5),d7
- and.b (IERstate,a3),d7 ;Quick check (note that this masking is very
- ;important)
- bne FastInt ;Service it
- endc
-
- ifge \2-1
- move.l (_Unit2,pc),a3
- move.l (daciabase,a3),a5
- move.b (ISR,a5),d7
- and.b (IERstate,a3),d7 ;Quick check (note that this masking is very
- ;important)
- bne FastInt ;Service it
- endc
-
- ifge \3-1
- move.l (Unit1,pc),a3
- move.l (daciabase,a3),a5
- move.b (ISR,a5),d7
- and.b (IERstate,a3),d7 ;Quick check (note that this masking is very
- ;important)
- bne FastInt ;Service it
- endc
-
- ifge \4-1
- move.l (Unit0,pc),a3
- move.l (daciabase,a3),a5
- move.b (ISR,a5),d7
- and.b (IERstate,a3),d7 ;Quick check (note that this masking is very
- ;important)
- bne FastInt ;Service it
- endc
-
- movem.l (sp)+,d0/d7/a0/a3/a5
- move.l (OldVec,pc),-(sp)
- rts
-
- endm
-
- IntRoutines:
- dc.l Int0000 ;dummy entry for 0
- dc.l Int0001
- dc.l Int0010
- dc.l Int0011
- dc.l Int0100
- dc.l Int0101
- dc.l Int0110
- dc.l Int0111
- dc.l Int1000
- dc.l Int1001
- dc.l Int1010
- dc.l Int1011
- dc.l Int1100
- dc.l Int1101
- dc.l Int1110
- dc.l Int1111
-
- ;************* Start of fast interrupt routine **************
-
- FastInt:
-
- ;****** NOTE/WARNING: Reading the ISR will cause the interrupt line
- ;****** to be deasserted, although the bits in the ISR (except for read
- ;****** error bits) will stay set ---- therefore simultaneous
- ;****** conditions MUST!!!! be checked for!!!!!! There is no
- ;****** second chance!
-
-
- ;Read error condition?
- ;(Note: Reading the RDR clears the error flags.)
- move.b d7,d0
- and.b #6,d0
- bne.b ReadErr ;read errors?
-
- btst #ISRB_RDRF,d7 ;Test Receive Data Buffer Full
- beq.b DoTDRE
-
- DoRDRF:
- ; PUTDEBUG 75,<'%s/Int: Read.'>
-
- ;Store the byte in the circular buffer. Note that this code *can't* be
- ;interrupted, so we're safe (that's because CIA B, which we're plugging into,
- ;is connected to INT6*).
-
- move.l (TailLong,a3),d0 ;Read and store
- move.l (StartBuf,a3),a0
- move.b (RDR,a5),(a0,d0.l)
- addq.w #1,(Tail,a3)
-
- ;Currently waiting for a character?
- btst #MDUB_WaitingForChar,(MDU_FLAGS,a3)
- bne.b SignalRead ;yes, signal read task
- bset #MDUB_CharAvailable,(MDU_FLAGS,a3)
-
- btst #ISRB_TDRE,d7
- bne.b DoTDRE
-
- ;Return from int routine
- movem.l (sp)+,d0/d7/a0/a3/a5
- move.w #$2000,(_custom+intreq)
- rte
-
- DoTDRE:
- ;Continue with int routine...
-
- ;We can deduce that the interrupt was caused by TDRE
- ;Therefore we have something to write...
-
- tst.l (WriteCount,a3)
- beq.b SetNeedChar
-
- bclr #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
- move.l (WriteBufferPtr,a3),a0
- move.b (a0)+,(TDR,a5)
- move.l a0,(WriteBufferPtr,a3)
- subq.l #1,(WriteCount,a3)
- beq.b DoneWriting
- EndInt: movem.l (sp)+,d0/d7/a0/a3/a5
- move.w #$2000,(_custom+intreq)
- rte
-
- SetNeedChar:
- bset #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
- bra.b EndInt
-
- ReadErr:
- bra.b RealReadErr
-
- SignalRead:
- bclr #MDUB_WaitingForChar,(MDU_FLAGS,a3)
- bset #MDUB_CharAvailable,(MDU_FLAGS,a3)
- movem.l d1/a1/a6,-(sp)
- movea.l (mdu_SysLib,a3),a6
- move.l (readsig,a3),d0
- lea (mdu_rtcb,a3),a1
- SYS Signal ;Signal the read task
- movem.l (sp)+,d1/a1/a6
-
- btst #ISRB_TDRE,d7
- bne DoTDRE
-
- movem.l (sp)+,d0/d7/a0/a3/a5
- move.l (OldVec,pc),-(sp)
- rts
-
- DoneWriting:
-
- ; PUTDEBUG 75,<'%s/Int: Write signal.'>
-
- movem.l d1/a1/a6,-(sp)
- move.l (tdresig,a3),d0
- lea (mdu_wtcb,a3),a1
- movea.l (mdu_SysLib,a3),a6
- SYS Signal ;Signal the write task
- movem.l (sp)+,d1/a1/a6
- movem.l (sp)+,d0/d7/a0/a3/a5
- move.l (OldVec,pc),-(sp)
- rts
-
- ;Exceptional conditions handled here....
-
- RealReadErr:
-
- ;An exceptional condition occured - signal the read task
- movem.l d1/a1/a6,-(sp)
- move.b d7,(ISRcopy,a3) ;Useful info
- move.b (CSR,a5),(CSRcopy,a3) ;More useful info
- move.l (readabortsig,a3),d0
- lea (mdu_rtcb,a3),a1
- movea.l (mdu_SysLib,a3),a6
- SYS Signal
- move.b (RDR,a5),d0 ;This forces a clear of the error bits
- movem.l (sp)+,d1/a1/a6
-
- btst #ISRB_RDRF,d7 ;Test Receive Data Buffer Full
- bne DoRDRF
- btst #ISRB_TDRE,d7
- bne DoTDRE
-
- movem.l (sp)+,d0/d7/a0/a3/a5
- move.l (OldVec,pc),-(sp)
- rts
-
- ;********* End of fast interrupt routine *********
-
- Int0000: DoInt 0,0,0,0
- Int0001: DoInt 0,0,0,1
- Int0010: DoInt 0,0,1,0
- Int0011: DoInt 0,0,1,1
- Int0100: DoInt 0,1,0,0
- Int0101: DoInt 0,1,0,1
- Int0110: DoInt 0,1,1,0
- Int0111: DoInt 0,1,1,1
- Int1000: DoInt 1,0,0,0
- Int1001: DoInt 1,0,0,1
- Int1010: DoInt 1,0,1,0
- Int1011: DoInt 1,0,1,1
- Int1100: DoInt 1,1,0,0
- Int1101: DoInt 1,1,0,1
- Int1110: DoInt 1,1,1,0
- Int1111: DoInt 1,1,1,1
-
-
- ifne INFO_LEVEL ;If any debugging enabled at all
-
- KPutFmt: move.l a2,-(sp)
- lea (KPutChar,pc),a2
- bsr.b KDoFmt
- movea.l (sp)+,a2
- rts
-
- KDoFmt: move.l a6,-(sp)
- movea.l (SysBase).w,a6
- SYS RawDoFmt
- movea.l (sp)+,a6
- rts
-
- KPutChar: move.l a6,-(sp)
- movea.l (SysBase).w,a6
- SYS RawPutChar
- movea.l (sp)+,a6
- rts
-
- endc
-
- EndCode:
- end
-